import os
import re
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from pathlib import Path
import json
from collections import defaultdict

class MarkdownAttributeEditor:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Markdown属性批量编辑器")
        self.root.geometry("1100x800")
        
        self.directory = None
        self.reference_directory = None
        self.md_files = []
        self.current_file_index = 0
        self.attribute_entries = {}
        self.attribute_references = defaultdict(set)
        
        # 定义属性字段
        self.attributes = [
            "tags", "type", "actor_id", "name", "aliases", 
            "link", "罩杯", "风格", "气质", "体型", "演技"
        ]
        
        # 数组类型的属性
        self.array_attributes = ["tags", "风格", "气质", "体型", "演技"]
        
        self.create_widgets()
    
    def create_widgets(self):
        # 创建笔记本（选项卡）
        notebook = ttk.Notebook(self.root)
        notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 单个文件编辑标签页
        self.single_frame = ttk.Frame(notebook)
        notebook.add(self.single_frame, text="单个文件编辑")
        
        # 批量处理标签页
        self.batch_frame = ttk.Frame(notebook)
        notebook.add(self.batch_frame, text="批量处理")
        
        # 初始化两个标签页
        self.create_single_file_tab()
        self.create_batch_processing_tab()
    
    def create_single_file_tab(self):
        """创建单个文件编辑标签页"""
        # 顶部按钮框架
        button_frame = tk.Frame(self.single_frame)
        button_frame.pack(pady=10)
        
        tk.Button(button_frame, text="选择编辑目录", command=self.select_edit_directory).pack(side=tk.LEFT, padx=2)
        tk.Button(button_frame, text="选择参考目录", command=self.select_reference_directory).pack(side=tk.LEFT, padx=2)
        tk.Button(button_frame, text="加载参考值", command=self.load_reference_values).pack(side=tk.LEFT, padx=2)
        tk.Button(button_frame, text="保存当前文件", command=self.save_current_file).pack(side=tk.LEFT, padx=2)
        
        # 目录状态显示
        status_frame = tk.Frame(self.single_frame)
        status_frame.pack(pady=5)
        
        self.edit_dir_label = tk.Label(status_frame, text="编辑目录: 未选择", fg="blue")
        self.edit_dir_label.pack(anchor="w")
        
        self.ref_dir_label = tk.Label(status_frame, text="参考目录: 未选择", fg="green")
        self.ref_dir_label.pack(anchor="w")
        
        self.ref_status_label = tk.Label(status_frame, text="参考值: 未加载", fg="red")
        self.ref_status_label.pack(anchor="w")
        
        # 文件导航框架
        nav_frame = tk.Frame(self.single_frame)
        nav_frame.pack(pady=5)
        
        self.file_label = tk.Label(nav_frame, text="未选择编辑目录")
        self.file_label.pack(side=tk.LEFT, padx=5)
        
        tk.Button(nav_frame, text="上一个", command=self.previous_file).pack(side=tk.LEFT, padx=2)
        tk.Button(nav_frame, text="下一个", command=self.next_file).pack(side=tk.LEFT, padx=2)
        
        # 属性编辑框架
        edit_frame = tk.Frame(self.single_frame)
        edit_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建滚动框架
        canvas = tk.Canvas(edit_frame)
        scrollbar = ttk.Scrollbar(edit_frame, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas)
        
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        self.create_attribute_fields()
    
    def create_batch_processing_tab(self):
        """创建批量处理标签页"""
        # 目录选择框架
        dir_frame = tk.LabelFrame(self.batch_frame, text="目录选择", padx=10, pady=10)
        dir_frame.pack(fill=tk.X, padx=10, pady=5)
        
        tk.Button(dir_frame, text="选择批量处理目录", command=self.select_batch_directory).pack(anchor="w")
        self.batch_dir_label = tk.Label(dir_frame, text="未选择目录", fg="blue")
        self.batch_dir_label.pack(anchor="w")
        
        # 参考目录框架
        ref_frame = tk.LabelFrame(self.batch_frame, text="参考值", padx=10, pady=10)
        ref_frame.pack(fill=tk.X, padx=10, pady=5)
        
        tk.Button(ref_frame, text="选择参考目录", command=self.select_batch_reference_directory).pack(anchor="w")
        self.batch_ref_dir_label = tk.Label(ref_frame, text="未选择参考目录", fg="green")
        self.batch_ref_dir_label.pack(anchor="w")
        
        tk.Button(ref_frame, text="加载参考值", command=self.load_batch_reference_values).pack(anchor="w")
        self.batch_ref_status_label = tk.Label(ref_frame, text="参考值: 未加载", fg="red")
        self.batch_ref_status_label.pack(anchor="w")
        
        # 批量操作框架
        action_frame = tk.LabelFrame(self.batch_frame, text="批量操作", padx=10, pady=10)
        action_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # 操作类型选择
        operation_frame = tk.Frame(action_frame)
        operation_frame.pack(fill=tk.X, pady=5)
        
        self.operation_var = tk.StringVar(value="add")
        
        tk.Radiobutton(operation_frame, text="批量添加", variable=self.operation_var, value="add").pack(side=tk.LEFT, padx=10)
        tk.Radiobutton(operation_frame, text="批量删除", variable=self.operation_var, value="delete").pack(side=tk.LEFT, padx=10)
        tk.Radiobutton(operation_frame, text="批量修改", variable=self.operation_var, value="modify").pack(side=tk.LEFT, padx=10)
        
        # 属性选择
        attr_frame = tk.Frame(action_frame)
        attr_frame.pack(fill=tk.X, pady=5)
        
        tk.Label(attr_frame, text="选择属性:").pack(side=tk.LEFT)
        self.batch_attr_var = tk.StringVar(value=self.attributes[0])
        attr_combo = ttk.Combobox(attr_frame, textvariable=self.batch_attr_var, values=self.attributes, width=15)
        attr_combo.pack(side=tk.LEFT, padx=5)
        
        # 值输入框架
        value_frame = tk.Frame(action_frame)
        value_frame.pack(fill=tk.X, pady=5)
        
        tk.Label(value_frame, text="值 A:").pack(side=tk.LEFT)
        self.value_a_entry = tk.Entry(value_frame, width=30)
        self.value_a_entry.pack(side=tk.LEFT, padx=5)
        
        tk.Label(value_frame, text="值 B:").pack(side=tk.LEFT)
        self.value_b_entry = tk.Entry(value_frame, width=30)
        self.value_b_entry.pack(side=tk.LEFT, padx=5)
        
        # 参考值按钮
        tk.Button(value_frame, text="参考值", command=self.show_batch_reference).pack(side=tk.LEFT, padx=5)
        
        # 选项框架
        option_frame = tk.Frame(action_frame)
        option_frame.pack(fill=tk.X, pady=5)
        
        self.case_sensitive_var = tk.BooleanVar(value=False)
        tk.Checkbutton(option_frame, text="区分大小写", variable=self.case_sensitive_var).pack(side=tk.LEFT, padx=10)
        
        self.trim_spaces_var = tk.BooleanVar(value=True)
        tk.Checkbutton(option_frame, text="去除首尾空格", variable=self.trim_spaces_var).pack(side=tk.LEFT, padx=10)
        
        # 预览框架
        preview_frame = tk.Frame(action_frame)
        preview_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        tk.Label(preview_frame, text="操作预览:").pack(anchor="w")
        
        self.preview_text = tk.Text(preview_frame, height=10)
        self.preview_text.pack(fill=tk.BOTH, expand=True)
        
        # 按钮框架
        button_frame = tk.Frame(action_frame)
        button_frame.pack(fill=tk.X, pady=10)
        
        tk.Button(button_frame, text="预览操作", command=self.preview_batch_operation).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="执行批量操作", command=self.execute_batch_operation, bg="#e6f3ff").pack(side=tk.LEFT, padx=5)
    
    def create_attribute_fields(self):
        """创建属性输入字段（单个文件编辑用）"""
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()
        
        for i, attr in enumerate(self.attributes):
            label_frame = tk.Frame(self.scrollable_frame)
            label_frame.grid(row=i, column=0, sticky="w", padx=5, pady=5)
            
            tk.Label(label_frame, text=f"{attr}:").pack(side=tk.LEFT)
            
            if attr in self.array_attributes:
                dedup_btn = tk.Button(
                    label_frame, 
                    text="去重", 
                    command=lambda a=attr: self.deduplicate_attribute(a),
                    width=4,
                    bg="#ffe6e6"
                )
                dedup_btn.pack(side=tk.LEFT, padx=5)
            
            if attr in self.array_attributes:
                entry = tk.Text(self.scrollable_frame, height=3, width=50)
                entry.bind("<FocusOut>", lambda e, a=attr: self.auto_deduplicate_attribute(a))
                self.attribute_entries[attr] = entry
                entry.grid(row=i, column=1, padx=5, pady=5, sticky="ew")
            else:
                entry = tk.Entry(self.scrollable_frame, width=50)
                self.attribute_entries[attr] = entry
                entry.grid(row=i, column=1, padx=5, pady=5, sticky="ew")
            
            ref_button = tk.Button(
                self.scrollable_frame, 
                text="参考", 
                command=lambda a=attr: self.show_attribute_reference(a),
                width=6,
                state="disabled"
            )
            ref_button.grid(row=i, column=2, padx=5, pady=5)
            self.attribute_entries[attr + "_button"] = ref_button
        
        self.scrollable_frame.columnconfigure(1, weight=1)
    
    # === 单个文件编辑相关方法 ===
    
    def select_edit_directory(self):
        """选择单个文件编辑的目录"""
        directory = filedialog.askdirectory(title="选择要编辑的Markdown文件目录")
        if directory:
            self.directory = directory
            self.edit_dir_label.config(text=f"编辑目录: {os.path.basename(directory)}")
            self.load_edit_files()
            if self.md_files:
                self.current_file_index = 0
                self.load_file_attributes()
            else:
                messagebox.showinfo("提示", "编辑目录中没有找到Markdown文件")
    
    def select_reference_directory(self):
        """选择参考目录（单个文件编辑用）"""
        directory = filedialog.askdirectory(title="选择参考目录")
        if directory:
            self.reference_directory = directory
            self.ref_dir_label.config(text=f"参考目录: {os.path.basename(directory)}")
    
    def load_edit_files(self):
        """加载编辑文件"""
        if not self.directory:
            return
        
        self.md_files = []
        for file_path in Path(self.directory).rglob("*.md"):
            self.md_files.append(file_path)
        
        self.file_label.config(text=f"文件: 1/{len(self.md_files)}")
    
    def load_reference_values(self):
        """加载参考值（单个文件编辑用）"""
        if not self.reference_directory:
            messagebox.showwarning("警告", "请先选择参考目录")
            return
        
        self.collect_attribute_references()
        self.update_reference_buttons_state()
        
        ref_count = sum(len(values) for values in self.attribute_references.values())
        loaded_count = sum(1 for values in self.attribute_references.values() if len(values) > 0)
        
        self.ref_status_label.config(
            text=f"参考值: 已加载 {ref_count} 个值",
            fg="green"
        )
        
        messagebox.showinfo("参考值已加载", f"已从参考目录中收集到 {ref_count} 个属性参考值")
    
    def update_reference_buttons_state(self):
        """更新参考按钮状态"""
        has_references = any(len(values) > 0 for values in self.attribute_references.values())
        
        for attr in self.attributes:
            button = self.attribute_entries.get(attr + "_button")
            if button:
                if has_references:
                    button.config(state="normal")
                else:
                    button.config(state="disabled")
    
    def show_attribute_reference(self, attribute):
        """显示属性参考值（单个文件编辑用）"""
        if not self.attribute_references[attribute]:
            messagebox.showinfo("参考", f"属性 '{attribute}' 没有可用的参考值")
            return
        
        ref_window = tk.Toplevel(self.root)
        ref_window.title(f"{attribute} 参考值")
        ref_window.geometry("400x300")
        
        listbox = tk.Listbox(ref_window)
        listbox.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        for value in sorted(self.attribute_references[attribute]):
            listbox.insert(tk.END, value)
        
        def insert_value():
            selection = listbox.curselection()
            if selection:
                value = listbox.get(selection[0])
                entry = self.attribute_entries[attribute]
                if isinstance(entry, tk.Text):
                    entry.insert(tk.END, f"\n{value}")
                else:
                    entry.delete(0, tk.END)
                    entry.insert(0, value)
                ref_window.destroy()
        
        tk.Button(ref_window, text="插入", command=insert_value).pack(pady=5)
        listbox.bind("<Double-Button-1>", lambda e: insert_value())
    
    def previous_file(self):
        """上一个文件"""
        if self.md_files and self.current_file_index > 0:
            self.current_file_index -= 1
            self.load_file_attributes()
    
    def next_file(self):
        """下一个文件"""
        if self.md_files and self.current_file_index < len(self.md_files) - 1:
            self.current_file_index += 1
            self.load_file_attributes()
    
    def load_file_attributes(self):
        """加载当前文件的属性"""
        if not self.md_files:
            return
        
        file_path = self.md_files[self.current_file_index]
        self.file_label.config(text=f"文件: {self.current_file_index + 1}/{len(self.md_files)} - {file_path.name}")
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            front_matter = self.parse_front_matter(content)
            
            for attr in self.attributes:
                entry = self.attribute_entries[attr]
                
                if isinstance(entry, tk.Text):
                    entry.delete(1.0, tk.END)
                else:
                    entry.delete(0, tk.END)
                
                if attr in front_matter:
                    value = front_matter[attr]
                    if isinstance(value, list):
                        if isinstance(entry, tk.Text):
                            entry.insert(1.0, "\n".join(value))
                        else:
                            entry.insert(0, ", ".join(value))
                    else:
                        if isinstance(entry, tk.Text):
                            entry.insert(1.0, str(value))
                        else:
                            entry.insert(0, str(value))
        except Exception as e:
            messagebox.showerror("错误", f"读取文件失败: {e}")
    
    def save_current_file(self):
        """保存当前文件"""
        if not self.md_files:
            return
        
        file_path = self.md_files[self.current_file_index]
        try:
            self.save_file_attributes(file_path)
            messagebox.showinfo("成功", f"已保存: {file_path.name}")
        except Exception as e:
            messagebox.showerror("错误", f"保存文件失败: {e}")
    
    # === 批量处理相关方法 ===
    
    def select_batch_directory(self):
        """选择批量处理目录"""
        directory = filedialog.askdirectory(title="选择批量处理的Markdown文件目录")
        if directory:
            self.directory = directory
            self.batch_dir_label.config(text=f"处理目录: {os.path.basename(directory)}")
            self.load_batch_files()
    
    def select_batch_reference_directory(self):
        """选择批量处理的参考目录"""
        directory = filedialog.askdirectory(title="选择参考目录")
        if directory:
            self.reference_directory = directory
            self.batch_ref_dir_label.config(text=f"参考目录: {os.path.basename(directory)}")
    
    def load_batch_files(self):
        """加载批量处理文件"""
        if not self.directory:
            return
        
        self.md_files = []
        for file_path in Path(self.directory).rglob("*.md"):
            self.md_files.append(file_path)
        
        self.batch_dir_label.config(text=f"处理目录: {os.path.basename(self.directory)} ({len(self.md_files)}个文件)")
    
    def load_batch_reference_values(self):
        """加载批量处理的参考值"""
        if not self.reference_directory:
            messagebox.showwarning("警告", "请先选择参考目录")
            return
        
        self.collect_attribute_references()
        
        ref_count = sum(len(values) for values in self.attribute_references.values())
        
        self.batch_ref_status_label.config(
            text=f"参考值: 已加载 {ref_count} 个值",
            fg="green"
        )
        
        messagebox.showinfo("参考值已加载", f"已从参考目录中收集到 {ref_count} 个属性参考值")
    
    def show_batch_reference(self):
        """显示批量处理的参考值"""
        attr = self.batch_attr_var.get()
        if not self.attribute_references[attr]:
            messagebox.showinfo("参考", f"属性 '{attr}' 没有可用的参考值")
            return
        
        ref_window = tk.Toplevel(self.root)
        ref_window.title(f"{attr} 参考值")
        ref_window.geometry("400x300")
        
        listbox = tk.Listbox(ref_window)
        listbox.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        for value in sorted(self.attribute_references[attr]):
            listbox.insert(tk.END, value)
        
        def insert_value():
            selection = listbox.curselection()
            if selection:
                value = listbox.get(selection[0])
                if self.operation_var.get() == "modify":
                    self.value_a_entry.delete(0, tk.END)
                    self.value_a_entry.insert(0, value)
                else:
                    self.value_a_entry.delete(0, tk.END)
                    self.value_a_entry.insert(0, value)
                ref_window.destroy()
        
        tk.Button(ref_window, text="插入", command=insert_value).pack(pady=5)
        listbox.bind("<Double-Button-1>", lambda e: insert_value())
    
    # === 通用方法 ===
    
    def collect_attribute_references(self):
        """收集属性参考值"""
        if not self.reference_directory:
            return
        
        for attr in self.attributes:
            self.attribute_references[attr].clear()
        
        reference_files = []
        for file_path in Path(self.reference_directory).rglob("*.md"):
            reference_files.append(file_path)
        
        for file_path in reference_files:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                
                front_matter = self.parse_front_matter(content)
                
                for attr in self.attributes:
                    if attr in front_matter:
                        value = front_matter[attr]
                        if isinstance(value, list):
                            for item in value:
                                if item and str(item).strip():
                                    self.attribute_references[attr].add(str(item).strip())
                        else:
                            if value and str(value).strip():
                                self.attribute_references[attr].add(str(value).strip())
            except Exception as e:
                print(f"读取参考文件失败 {file_path}: {e}")
    
    def parse_front_matter(self, content):
        """解析front matter"""
        front_matter = {}
        match = re.search(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
        if match:
            front_matter_text = match.group(1)
            lines = front_matter_text.split('\n')
            current_key = None
            current_list = []
            
            for line in lines:
                line = line.strip()
                if not line:
                    continue
                
                if ':' in line and not line.startswith(' '):
                    if current_key and current_list:
                        front_matter[current_key] = current_list
                        current_list = []
                    
                    key, value = line.split(':', 1)
                    key = key.strip()
                    value = value.strip()
                    
                    if value.startswith('[') and value.endswith(']'):
                        try:
                            front_matter[key] = json.loads(value)
                        except:
                            items = value[1:-1].split(',')
                            front_matter[key] = [item.strip() for item in items if item.strip()]
                    elif value.startswith('-'):
                        current_key = key
                        current_list = [value[1:].strip()]
                    elif value:
                        front_matter[key] = value
                    else:
                        current_key = key
                        current_list = []
                elif line.startswith('- ') and current_key:
                    current_list.append(line[2:].strip())
            
            if current_key and current_list:
                front_matter[current_key] = current_list
        
        return front_matter
    
    def save_file_attributes(self, file_path):
        """保存文件属性"""
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        front_matter_match = re.search(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
        
        if front_matter_match:
            old_front_matter = front_matter_match.group(0)
            new_front_matter = self.generate_front_matter()
            content = content.replace(old_front_matter, new_front_matter)
        else:
            new_front_matter = self.generate_front_matter()
            content = new_front_matter + '\n' + content
        
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(content)
    
    def generate_front_matter(self):
        """生成front matter"""
        front_matter_lines = ["---"]
        
        for attr in self.attributes:
            entry = self.attribute_entries[attr]
            
            if isinstance(entry, tk.Text):
                value = entry.get(1.0, tk.END).strip()
            else:
                value = entry.get().strip()
            
            if value:
                if attr in self.array_attributes:
                    items = [line.strip() for line in value.split('\n') if line.strip()]
                    if items:
                        front_matter_lines.append(f"{attr}:")
                        for item in items:
                            front_matter_lines.append(f"  - {item}")
                else:
                    front_matter_lines.append(f"{attr}: {value}")
        
        front_matter_lines.append("---")
        return "\n".join(front_matter_lines)
    
    def generate_content_with_front_matter(self, content, front_matter):
        """用新的front matter生成内容"""
        front_matter_match = re.search(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
        
        if front_matter_match:
            old_front_matter = front_matter_match.group(0)
            new_front_matter = self.front_matter_to_string(front_matter)
            return content.replace(old_front_matter, new_front_matter)
        else:
            new_front_matter = self.front_matter_to_string(front_matter)
            return new_front_matter + '\n' + content
    
    def front_matter_to_string(self, front_matter):
        """将front matter字典转换为字符串"""
        lines = ["---"]
        for key, value in front_matter.items():
            if value is None:
                continue
            if isinstance(value, list):
                if value:
                    lines.append(f"{key}:")
                    for item in value:
                        lines.append(f"  - {item}")
            else:
                lines.append(f"{key}: {value}")
        lines.append("---")
        return "\n".join(lines)
    
    # === 去重相关方法 ===
    
    def auto_deduplicate_attribute(self, attribute):
        """自动去重属性"""
        if attribute not in self.array_attributes:
            return
        
        entry = self.attribute_entries[attribute]
        content = entry.get(1.0, tk.END).strip()
        
        if content:
            lines = [line.strip() for line in content.split('\n') if line.strip()]
            deduplicated_lines = self.deduplicate_values(lines)
            
            if len(deduplicated_lines) != len(lines):
                new_content = "\n".join(deduplicated_lines)
                entry.delete(1.0, tk.END)
                entry.insert(1.0, new_content)
    
    def deduplicate_attribute(self, attribute):
        """手动去重属性"""
        if attribute not in self.array_attributes:
            return
        
        entry = self.attribute_entries[attribute]
        content = entry.get(1.0, tk.END).strip()
        
        if content:
            lines = [line.strip() for line in content.split('\n') if line.strip()]
            original_count = len(lines)
            deduplicated_lines = self.deduplicate_values(lines)
            
            if len(deduplicated_lines) < original_count:
                new_content = "\n".join(deduplicated_lines)
                entry.delete(1.0, tk.END)
                entry.insert(1.0, new_content)
                messagebox.showinfo("去重完成", f"去除 {original_count - len(deduplicated_lines)} 个重复项")
            else:
                messagebox.showinfo("去重完成", "没有发现重复项")
    
    def deduplicate_values(self, values, case_sensitive=False, trim_spaces=True):
        """去重值列表"""
        seen = set()
        result = []
        
        for value in values:
            if value:
                processed_value = str(value)
                if trim_spaces:
                    processed_value = processed_value.strip()
                if not case_sensitive:
                    processed_value = processed_value.lower()
                
                if processed_value and processed_value not in seen:
                    seen.add(processed_value)
                    result.append(value)
        
        return result
    
    # === 批量操作相关方法 ===
    
    def preview_batch_operation(self):
        """预览批量操作"""
        if not self.md_files:
            messagebox.showwarning("警告", "请先选择处理目录")
            return
        
        attr = self.batch_attr_var.get()
        value_a = self.value_a_entry.get().strip()
        operation = self.operation_var.get()
        
        if not value_a and operation != "delete":
            messagebox.showwarning("警告", "请输入值A")
            return
        
        if operation == "modify":
            value_b = self.value_b_entry.get().strip()
            if not value_b:
                messagebox.showwarning("警告", "修改操作需要输入值B")
                return
        
        affected_files = []
        for file_path in self.md_files:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                
                front_matter = self.parse_front_matter(content)
                will_be_affected = False
                
                if operation == "add":
                    will_be_affected = self.will_be_affected_by_add(front_matter, attr, value_a)
                elif operation == "delete":
                    will_be_affected = self.will_be_affected_by_delete(front_matter, attr, value_a)
                elif operation == "modify":
                    will_be_affected = self.will_be_affected_by_modify(front_matter, attr, value_a, value_b)
                
                if will_be_affected:
                    affected_files.append(file_path.name)
                    
            except Exception as e:
                print(f"分析文件失败 {file_path}: {e}")
        
        self.preview_text.delete(1.0, tk.END)
        self.preview_text.insert(1.0, 
            f"操作类型: {self.get_operation_name(operation)}\n"
            f"属性: {attr}\n"
            f"值A: {value_a if value_a else '所有值'}\n"
            f"值B: {self.value_b_entry.get().strip() if operation == 'modify' else 'N/A'}\n"
            f"影响文件数: {len(affected_files)}/{len(self.md_files)}\n\n"
            f"受影响文件:\n" + "\n".join(affected_files[:10]) + 
            (f"\n... 还有 {len(affected_files)-10} 个文件" if len(affected_files) > 10 else "")
        )
    
    def will_be_affected_by_add(self, front_matter, attr, value):
        if attr not in front_matter:
            return True
        
        current_values = front_matter[attr]
        if not isinstance(current_values, list):
            current_values = [current_values]
        
        return not self.value_exists(current_values, value)
    
    def will_be_affected_by_delete(self, front_matter, attr, value):
        if attr not in front_matter:
            return False
        
        current_values = front_matter[attr]
        if not isinstance(current_values, list):
            current_values = [current_values]
        
        if not value:
            return True
        
        return self.value_exists(current_values, value)
    
    def will_be_affected_by_modify(self, front_matter, attr, value_a, value_b):
        if attr not in front_matter:
            return False
        
        current_values = front_matter[attr]
        if not isinstance(current_values, list):
            current_values = [current_values]
        
        has_value_a = self.value_exists(current_values, value_a)
        has_value_b = self.value_exists(current_values, value_b) if value_b != value_a else True
        
        return has_value_a and not has_value_b
    
    def value_exists(self, values, target_value):
        if not target_value:
            return False
        
        case_sensitive = self.case_sensitive_var.get()
        trim_spaces = self.trim_spaces_var.get()
        
        for value in values:
            processed_value = str(value)
            processed_target = str(target_value)
            
            if trim_spaces:
                processed_value = processed_value.strip()
                processed_target = processed_target.strip()
            
            if not case_sensitive:
                processed_value = processed_value.lower()
                processed_target = processed_target.lower()
            
            if processed_value == processed_target:
                return True
        
        return False
    
    def execute_batch_operation(self):
        """执行批量操作"""
        if not self.md_files:
            messagebox.showwarning("警告", "请先选择处理目录")
            return
        
        attr = self.batch_attr_var.get()
        value_a = self.value_a_entry.get().strip()
        value_b = self.value_b_entry.get().strip()
        operation = self.operation_var.get()
        
        if operation != "delete" and not value_a:
            messagebox.showwarning("警告", "请输入值A")
            return
        
        if operation == "modify" and not value_b:
            messagebox.showwarning("警告", "修改操作需要输入值B")
            return
        
        result = messagebox.askyesno("确认", 
            f"确定要执行批量操作吗？\n"
            f"操作: {self.get_operation_name(operation)}\n"
            f"属性: {attr}\n"
            f"影响文件数: {len(self.md_files)}"
        )
        
        if not result:
            return
        
        processed_count = 0
        for file_path in self.md_files:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                
                front_matter = self.parse_front_matter(content)
                modified = False
                
                if operation == "add":
                    modified = self.apply_add_operation(front_matter, attr, value_a)
                elif operation == "delete":
                    modified = self.apply_delete_operation(front_matter, attr, value_a)
                elif operation == "modify":
                    modified = self.apply_modify_operation(front_matter, attr, value_a, value_b)
                
                if modified:
                    new_content = self.generate_content_with_front_matter(content, front_matter)
                    with open(file_path, 'w', encoding='utf-8') as f:
                        f.write(new_content)
                    processed_count += 1
                    
            except Exception as e:
                print(f"处理文件失败 {file_path}: {e}")
        
        messagebox.showinfo("完成", f"批量操作完成！\n成功处理 {processed_count}/{len(self.md_files)} 个文件")
        self.preview_batch_operation()
    
    def apply_add_operation(self, front_matter, attr, value):
        if attr not in front_matter:
            front_matter[attr] = [value] if attr in self.array_attributes else value
            return True
        
        current_values = front_matter[attr]
        if attr in self.array_attributes:
            if not isinstance(current_values, list):
                current_values = [current_values]
            
            if not self.value_exists(current_values, value):
                current_values.append(value)
                front_matter[attr] = current_values
                return True
        else:
            if not current_values:
                front_matter[attr] = value
                return True
        
        return False
    
    def apply_delete_operation(self, front_matter, attr, value):
        if attr not in front_matter:
            return False
        
        if not value:
            del front_matter[attr]
            return True
        
        current_values = front_matter[attr]
        if attr in self.array_attributes:
            if not isinstance(current_values, list):
                current_values = [current_values]
            
            new_values = []
            for val in current_values:
                if not self.value_exists([val], value):
                    new_values.append(val)
            
            if len(new_values) != len(current_values):
                front_matter[attr] = new_values if new_values else None
                return True
        else:
            if self.value_exists([current_values], value):
                front_matter[attr] = None
                return True
        
        return False
    
    def apply_modify_operation(self, front_matter, attr, value_a, value_b):
        if attr not in front_matter:
            return False
        
        current_values = front_matter[attr]
        modified = False
        
        if attr in self.array_attributes:
            if not isinstance(current_values, list):
                current_values = [current_values]
            
            new_values = []
            for val in current_values:
                if self.value_exists([val], value_a):
                    new_values.append(value_b)
                    modified = True
                else:
                    new_values.append(val)
            
            if modified:
                front_matter[attr] = new_values
        else:
            if self.value_exists([current_values], value_a):
                front_matter[attr] = value_b
                modified = True
        
        return modified
    
    def get_operation_name(self, operation):
        names = {
            "add": "批量添加",
            "delete": "批量删除", 
            "modify": "批量修改"
        }
        return names.get(operation, "未知操作")
    
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    editor = MarkdownAttributeEditor()
    editor.run()